package mn.more.foundation.web;

import java.io.IOException;
import java.util.Enumeration;
import java.util.Locale;
import javax.servlet.ServletConfig;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

/**
 * @author $Author: mikeliucc $
 * @version $Id: SnoopServlet.java 5 2008-09-01 12:08:42Z mikeliucc $
 */
public class SnoopServlet extends HttpServlet {

	private static final String STYLESHEET = "/themes/current/styles/snoop.css";
	private static final String JAVASCRIPT = "/themes/current/scripts/snoop.js";

	@Override
	public String getServletInfo() { return "Snoop Servlet"; }

	protected void service(HttpServletRequest request,
	                       HttpServletResponse response)
		throws ServletException, IOException {
		response.setContentType("text/html");

		StringBuilder sb = new StringBuilder(10240 * 3);// guestimate
		SnoopUtil.createHtmlHeader(sb,
		                           getServletInfo(),
		                           STYLESHEET,
		                           JAVASCRIPT);
		createRequestReport(sb, request);
		createSessionReport(sb, request);
		createServletReport(sb, getServletConfig());
		createContextReport(sb, getServletContext());
		SnoopUtil.createHtmlFooter(sb);

		response.setContentLength(sb.length());
		response.getOutputStream().print(sb.toString());
	}

	public void destroy() {
		super.destroy();
	}

	public void init(ServletConfig config) throws ServletException {
		super.init(config);
	}

	public static void createServletReport(StringBuilder sb,
	                                       ServletConfig config) {
		SnoopUtil.addTitle(sb, "Servlet");

		SnoopUtil.startTable(sb);
		SnoopUtil.addCellRow(sb, "Servlet Name", config.getServletName());

		Enumeration headers = config.getInitParameterNames();
		if (headers == null) {
			SnoopUtil.addNoDataCell(sb);
		} else {
			while (headers.hasMoreElements()) {
				Object key = headers.nextElement();
				if (key != null) {
					SnoopUtil.addCellRow(sb,
					                     "init:: " + key,
					                     config.getInitParameter(key.toString()));
				}
			}
		}
		SnoopUtil.endTable(sb);
	}

	public static void createRequestReport(StringBuilder sb,
	                                       HttpServletRequest request) {
		SnoopUtil.addTitle(sb, "HTTP Request Information");

		SnoopUtil.startTable(sb);
		addRequestServerReport(sb, request);
		addRequestAttributeReport(sb, request);
		addRequestClientReport(sb, request);
		addRequestHeaderReport(sb, request);
		addRequestParamsReport(sb, request);
		addCookieReport(sb, request);
		SnoopUtil.endTable(sb);
	}

	public static void addRequestAttributeReport(StringBuilder sb,
	                                             HttpServletRequest request) {
		Enumeration enumeration = request.getAttributeNames();
		if (enumeration.hasMoreElements()) {
			while (enumeration.hasMoreElements()) {
				String name = (String) enumeration.nextElement();
				SnoopUtil.addCellRow(sb, "attr:: " + name, SnoopUtil.toString(
					request.getAttribute(name)));
			}
		}
	}

	public static void addRequestParamsReport(StringBuilder sb,
	                                          HttpServletRequest request) {
		SnoopUtil.addCellRow(sb,
		                     "params:: Query string",
		                     request.getQueryString());
		Enumeration enumeration = request.getParameterNames();
		if (enumeration != null) {
			while (enumeration.hasMoreElements()) {
				String name = (String) enumeration.nextElement();
				String[] vals = request.getParameterValues(name);
				SnoopUtil.addCellRow(sb, "params:: " + name, SnoopUtil.toString(
					vals));
			}
		}
	}

	public static void addRequestHeaderReport(StringBuilder sb,
	                                          HttpServletRequest request) {
		Enumeration headers = request.getHeaderNames();
		if (headers != null) {
			while (headers.hasMoreElements()) {
				Object key = headers.nextElement();
				if (key != null) {
					SnoopUtil.addCellRow(sb,
					                     "header:: " + key,
					                     request.getHeader(key.toString()));
				}
			}
		}
	}

	public static void createSessionReport(StringBuilder sb,
	                                       HttpServletRequest request) {
		SnoopUtil.addTitle(sb, "HTTP Session Information");
		SnoopUtil.startTable(sb);

		HttpSession session = request.getSession(false);
		if (session == null) {
			SnoopUtil.addNoDataCell(sb);
		} else {
			SnoopUtil.addCellRow(sb, "ID", session.getId());
			SnoopUtil.addCellRow(sb,
			                     "Creation Time",
			                     session.getCreationTime());
			SnoopUtil.addCellRow(sb,
			                     "Last Accesed Time",
			                     session.getLastAccessedTime());
			String mechanism = "unknown";
			if (request.isRequestedSessionIdFromCookie()) {
				mechanism = "cookie";
			} else if (request.isRequestedSessionIdFromURL()) {
				mechanism = "url-encoding";
			}
			SnoopUtil.addCellRow(sb, "Tracking Mechanism", mechanism);

			Enumeration vals = session.getAttributeNames();
			if (vals.hasMoreElements()) {
				while (vals.hasMoreElements()) {
					String name = (String) vals.nextElement();
					SnoopUtil.addCellRow(sb,
					                     "value:: " + name,
					                     SnoopUtil.toString(session.getAttribute(
						                     name)));
				}
			}
		}

		SnoopUtil.endTable(sb);
	}

	public static void addRequestClientReport(StringBuilder sb,
	                                          HttpServletRequest request) {
		SnoopUtil.addCellRow(sb, "URL", request.getRequestURL().toString());
		SnoopUtil.addCellRow(sb, "request:: URI", request.getRequestURI());
		SnoopUtil.addCellRow(sb, "request:: protocol", request.getProtocol());
		SnoopUtil.addCellRow(sb, "request:: method", request.getMethod());
		SnoopUtil.addCellRow(sb, "request:: Path info", request.getPathInfo());
		SnoopUtil.addCellRow(sb,
		                     "request:: Content length",
		                     request.getContentLength());
		SnoopUtil.addCellRow(sb,
		                     "request:: Content type",
		                     request.getContentType());
		SnoopUtil.addCellRow(sb,
		                     "request:: Character encoding",
		                     request.getCharacterEncoding());
		SnoopUtil.addCellRow(sb,
		                     "request:: Preferred Client Locale",
		                     request.getLocale());
		Enumeration locales = request.getLocales();
		while (locales.hasMoreElements()) {
			SnoopUtil.addCellRow(sb,
			                     "request:: All Client Locales",
			                     (Locale) locales.nextElement());
		}
		SnoopUtil.addCellRow(sb,
		                     "request:: Remote address",
		                     request.getRemoteAddr());
		SnoopUtil.addCellRow(sb,
		                     "request:: Remote host",
		                     request.getRemoteHost());
		SnoopUtil.addCellRow(sb,
		                     "request:: Remote user",
		                     request.getRemoteUser());
		SnoopUtil.addCellRow(sb,
		                     "request:: Authorization scheme",
		                     request.getAuthType());
		SnoopUtil.addCellRow(sb,
		                     "request:: User Principal",
		                     request.getUserPrincipal());
	}

	public static void addRequestServerReport(StringBuilder sb,
	                                          HttpServletRequest request) {
		SnoopUtil.addCellRow(sb,
		                     "request:: Servlet path",
		                     request.getServletPath());
		SnoopUtil.addCellRow(sb,
		                     "request:: Server name",
		                     request.getServerName());
		SnoopUtil.addCellRow(sb,
		                     "request:: Server port",
		                     request.getServerPort());
		SnoopUtil.addCellRow(sb,
		                     "request:: Path translated",
		                     request.getPathTranslated());
		SnoopUtil.addCellRow(sb,
		                     "request:: Context Path",
		                     request.getContextPath());
	}

	public static void addCookieReport(StringBuilder sb,
	                                   HttpServletRequest request) {
		Cookie[] cookies = request.getCookies();
		if (cookies != null) {
			for (Cookie cookie : cookies) {
				SnoopUtil.addCellRow(sb,
				                     "cookie:: " + cookie.getName(),
				                     cookie.getValue());
			}
		}
	}

	public static void createContextReport(StringBuilder sb,
	                                       ServletContext context) {
		SnoopUtil.addTitle(sb, "Servlet Context");

		SnoopUtil.startTable(sb);
		Enumeration headers = context.getInitParameterNames();
		if (headers == null) {
			SnoopUtil.addNoDataCell(sb);
		} else {
			while (headers.hasMoreElements()) {
				Object key = headers.nextElement();
				if (key != null) {
					SnoopUtil.addCellRow(sb,
					                     "init:: " + key,
					                     context.getInitParameter(key.toString()));
				}
			}
		}

		addContextAttributeReport(sb, context);
		SnoopUtil.endTable(sb);
	}

	public static void addContextAttributeReport(StringBuilder sb,
	                                             ServletContext context) {
		SnoopUtil.addCellRow(sb, "attr:: Server Info", context.getServerInfo());
		SnoopUtil.addCellRow(sb,
		                     "attr:: Major Version",
		                     context.getMajorVersion());
		SnoopUtil.addCellRow(sb,
		                     "attr:: Minor Version",
		                     context.getMinorVersion());
		SnoopUtil.addCellRow(sb,
		                     "attr:: Servlet Context Name",
		                     context.getServletContextName());
		Enumeration headers = context.getAttributeNames();
		if (headers != null) {
			while (headers.hasMoreElements()) {
				Object key = headers.nextElement();
				if (key != null) {
					SnoopUtil.addCellRow(sb,
					                     "attr:: " + key,
					                     context.getAttribute(key.toString()));
				}
			}
		}
		SnoopUtil.endTable(sb);
	}

	public static void createServerFileReport(StringBuilder sb,
	                                          String title,
	                                          String[] searchIn) {
		SnoopUtil.addTitle(sb, title);
		SnoopUtil.startTable(sb);
		StringBuilder result = SnoopUtil.getServerFile(searchIn);
		SnoopUtil.addCellRow(sb, title, result.toString());
		SnoopUtil.endTable(sb);
	}

}
